﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.IO.Ports;


namespace MecanumAssistant
{
    public partial class MecanumAssistant : Form
    {
        public class Wave
        {
            public float[] imu = new float[3]; 
            public float[] vel = new float[3];
            public float[] wheel = new float[4];
            public float[] user_data = new float[4];

            public int sizeMax = 0;
            public List<int>[] DataL = new List<int>[14];
            public Point[,] pArrData;
        }
        public Wave wave = new Wave();
        //存放数据的数组最大值
        //private int sizeMax;
        //存放y轴数据的数组链表
        private List<int> DataL;
        //存放在画布上的数据节点的数组
        private Point[] pArrData;
        public MecanumAssistant()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;

            wave.sizeMax = (pcbDisplay.Width - pcbDisplay.Width / N) ;
            DataL = new List<int>();
            pArrData = new Point[wave.sizeMax + 1];
            wave.pArrData = new Point[14, wave.sizeMax + 1];
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            port_comboBox.Items.Clear();
            try
            {
                port_comboBox.Text = System.IO.Ports.SerialPort.GetPortNames()[0];
            }
            catch
            {
                port_comboBox.Text = "";
            }
            Draw(0, 0, 0);

            new Thread(SerialRead_Thread)
            {
                IsBackground = true
            }.Start();
        }
        private void Form1_Resize(object sender, EventArgs e)
        {
            Draw(0, 0, 0);
            wave.sizeMax = (pcbDisplay.Width - pcbDisplay.Width / N);
            pArrData = new Point[wave.sizeMax + 1];
        }

        private void SerialRead_Thread()
        {
            while (true)
            {
                if (serialPort1.IsOpen)
                {
                    {
                        try
                        {
                            int data = serialPort1.ReadByte();
                            Serial_GetOneByte(data);
                            if (tabControl1.SelectedTab != tabControl1.TabPages[0])
                            {
                                if (rdb_ascii.Checked == true)
                                {
                                    string s = new string((char)data, 1);
                                    txbReceive.AppendText(s);
                                }
                                else if (rdb_hex.Checked == true)
                                {
                                    string s = Convert.ToString(data, 16).ToUpper();
                                    txbReceive.AppendText((s.Length == 1 ? "0" + s : s) + " ");
                                }
                            }

                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }
                    }
                }
            }
        }
        
        enum SerialDataType { IMU = 0, VEL, WHEEL, USER};
        public class Serial
        {
            public int state = 0;
            public int cnt = 0;
            public byte[] data_receive = new byte[100];
            public int data_type = (int)SerialDataType.IMU;
            public Mutex mutex = new Mutex();
        }
        
        Serial serial = new Serial();
        private void Serial_GetOneByte(int data32)
        {
            //Console.WriteLine(data32);
            if(serial.state == 0 && data32 == 0xAA)
            {
                serial.state = 1;
            }
            else if (serial.state == 1)
            {
                serial.state = 2;
                switch (data32)
                {
                    case 0xBB: serial.data_type = (int)SerialDataType.IMU; break;
                    case 0xCC: serial.data_type = (int)SerialDataType.VEL; break;
                    case 0xDD: serial.data_type = (int)SerialDataType.WHEEL; break;
                    case 0xEE: serial.data_type = (int)SerialDataType.USER; break;
                    default: serial.state = 0; break;
                }                
            }
            else if (serial.state == 2)
            {
                serial.data_receive[serial.cnt++] = (byte)data32;
                int data_size = serial.data_type < 2 ? 13 : 17; // 最后一字节为校验码
                if (serial.cnt >= data_size)
                {
                    byte checkout = 0;
                    for (int i = 0; i < data_size - 1; i++)
                    {
                        checkout += serial.data_receive[i];
                    }
                    //Console.WriteLine(checkout + " " + serial.data_receive[data_size - 1]);
                    if (checkout == serial.data_receive[data_size - 1])
                    {
                        // 校验通过，进行解码
                        if (serial.data_type == (int)SerialDataType.IMU)
                        {
                            wave.imu[0] = BitConverter.ToSingle(serial.data_receive, 0);
                            wave.imu[1] = BitConverter.ToSingle(serial.data_receive, 4);
                            wave.imu[2] = BitConverter.ToSingle(serial.data_receive, 8);
                            label_1.Text = wave.imu[0].ToString();
                            label_2.Text = wave.imu[1].ToString();
                            label_3.Text = wave.imu[2].ToString();
                        }
                        else if (serial.data_type == (int)SerialDataType.VEL)
                        {
                            wave.vel[0] = BitConverter.ToSingle(serial.data_receive, 0);
                            wave.vel[1] = BitConverter.ToSingle(serial.data_receive, 4);
                            wave.vel[2] = BitConverter.ToSingle(serial.data_receive, 8);
                            label_4.Text = wave.vel[0].ToString();
                            label_5.Text = wave.vel[1].ToString();
                            label_6.Text = wave.vel[2].ToString();
                        }
                        else if (serial.data_type == (int)SerialDataType.WHEEL)
                        {
                            wave.wheel[0] = BitConverter.ToSingle(serial.data_receive, 0);
                            wave.wheel[1] = BitConverter.ToSingle(serial.data_receive, 4);
                            wave.wheel[2] = BitConverter.ToSingle(serial.data_receive, 8);
                            wave.wheel[3] = BitConverter.ToSingle(serial.data_receive, 12);
                            label_7.Text  = wave.wheel[0].ToString();
                            label_8.Text  = wave.wheel[1].ToString();
                            label_9.Text  = wave.wheel[2].ToString();
                            label_10.Text = wave.wheel[3].ToString();
                        }
                        else if (serial.data_type == (int)SerialDataType.USER)
                        {
                            wave.user_data[0] = BitConverter.ToSingle(serial.data_receive, 0);
                            wave.user_data[1] = BitConverter.ToSingle(serial.data_receive, 4);
                            wave.user_data[2] = BitConverter.ToSingle(serial.data_receive, 8);
                            wave.user_data[3] = BitConverter.ToSingle(serial.data_receive, 12);
                            label_11.Text = wave.user_data[0].ToString();
                            label_12.Text = wave.user_data[1].ToString();
                            label_13.Text = wave.user_data[2].ToString();
                            label_14.Text = wave.user_data[3].ToString();
                        }

                    }

                    ;
                    DrawWave(wave.DataL[0], wave.wheel[0]);
                    serial.state = 0;
                    serial.cnt = 0;
                }
            }
        }

        private void DrawWave(List<int> list, float data)
        {
            DataL.Add((int)(data));
            while (DataL.Count >= wave.sizeMax + 1)
            {
                DataL.RemoveAt(0);
            }
            if (DataL.Count != 0)
            {
                pArrData = new Point[DataL.Count];
            }
            for (int i = 0; i < wave.sizeMax + 1; i++)
            {
                if (i >= DataL.Count)
                {
                    break;
                }
                pArrData[i] = new Point((i + wave.sizeMax / N), -DataL[i] + pcbDisplay.Height / 2);
                
            }
            pcbDisplay.Refresh();
        }

        private void connect_btn_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)
            {                
                serialPort1.Close();
                connect_btn.Text = "X";
                connect_btn.BackColor = Color.Red;
                baud_comboBox.Enabled = true;
                port_comboBox.Enabled = true;
            }
            else
            {
                try
                {
                    serialPort1.PortName = port_comboBox.Text;
                    serialPort1.BaudRate = Convert.ToInt32(baud_comboBox.Text);
                    serialPort1.DataBits = 8;

                    serialPort1.Open();
                    connect_btn.Text = "〇";
                    connect_btn.BackColor = Color.SpringGreen;
                    baud_comboBox.Enabled = false;
                    port_comboBox.Enabled = false;

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void port_refresh(object sender, EventArgs e)
        {
            port_comboBox.Items.Clear();
            port_comboBox.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
            
        }

        
        //定义画笔
        private Pen greenPen = new Pen(Color.Green, 1);
        private Pen redPen = new Pen(Color.Red, 1);
        private Pen blackPen = new Pen(Color.Black, 1);
        private Pen grayPen = new Pen(Color.Gray, 1);
        //private Pen tempPen = new Pen(Color.BurlyWood, 1);
        private Pen tempPen = new Pen(Color.Brown, 1);

        private Pen[] wavePen = new Pen[14];
        void pen_init()
        {
            wavePen[0] = new Pen(Color.FromArgb(0, 0, 255), 2);
            wavePen[1] = new Pen(Color.FromArgb(0, 0, 255), 2);
            wavePen[2] = new Pen(Color.FromArgb(0, 0, 255), 2);
            wavePen[3] = new Pen(Color.FromArgb(0, 0, 255), 2);
        }

        private void pcbDisplay_Paint(object sender, PaintEventArgs e)
        {
            
            if (DataL.Count != 1)
            {
                e.Graphics.DrawCurve(redPen, pArrData);
            }
        }
        private void pcbDisplay_MouseMove(object sender, MouseEventArgs e)
        {
            int ex = e.X;
            int ey = e.Y;
            Draw(ex, ey, 1);
        }
        int N = 10;
        Font font = new Font("微软雅黑", 9, FontStyle.Regular);
        Brush brush = new SolidBrush(Color.Blue);
        private void Draw(int x, int y, int flag)//, int[] xbuf, int[] ybuf)
        {
            
            int height = pcbDisplay.Height;
            int width = pcbDisplay.Width;
            Bitmap image = new Bitmap(width, height);
            Graphics g = Graphics.FromImage(image);
            g.Clear(Color.White);


            // 画方框
            g.DrawLine(blackPen, width / N, height - 1, width, height - 1);
            g.DrawLine(blackPen, width - 1, 0, width - 1, height);
            g.DrawLine(blackPen, width / N, 0, width, 0);
            g.DrawLine(blackPen, width / N, 0, width / N, height);

            // 画网格
            for (int i = 1; i < N; i++)
            {
                int px = i * width / N;
                int py = i * height / N;
                
                g.DrawString((-py+height/2).ToString(), font, brush, 0.04f * width, py - 0.02f * height);
                // 横线
                g.DrawLine(grayPen, width / N, py, width, py);
                // 纵线
                //g.DrawLine(grayPen, px, 0, px, height);
            }

            if (flag == 1)
            {
                if (x > width / N)
                { 
                    // 画鼠标十字
                    g.DrawLine(tempPen, x, 0, x, height);
                    g.DrawLine(greenPen, width / N, y, width, y);
                    g.DrawString("坐标：\r\nx=" + x.ToString() + "\r\ny=" + (-y + height / 2).ToString(), font, brush, x, y);
                    pcbDisplay.Cursor = Cursors.Cross;
                }
                else
                {
                    pcbDisplay.Cursor = Cursors.Default;
                }
            }
            pcbDisplay.Image = image;
        }
        private void Wave_Select(object sender, EventArgs e)
        {
            if(checkBox1.Checked)
            Console.WriteLine("hello");
        }

        private byte[] get_data_to_send(float[] data32, int cnt)
        {
            byte[] data_to_send = new byte[100];
            data_to_send[0] = 0xAA;
            byte checkout = 0;

            for (int k = 0; k < cnt; k++)
            {                
                byte[] data8 = BitConverter.GetBytes(data32[k]);
                data8.CopyTo(data_to_send, k * 4 + 1);
                for (int i = 0; i < 4; i++)
                {
                    checkout += data8[i];
                }
            }
            data_to_send[4 * cnt + 1] = checkout;
            
            return data_to_send;
        }

        private void btn_set_vel_Click(object sender, EventArgs e)
        {
            try
            {
                int cnt = 0;

                float[] data32 = new float[100];
                data32[cnt++] = Convert.ToSingle(txb_set_1.Text);
                data32[cnt++] = Convert.ToSingle(txb_set_2.Text);
                data32[cnt++] = Convert.ToSingle(txb_set_3.Text);

                byte[] data_to_send = get_data_to_send(data32, cnt);

                serialPort1.Write(data_to_send, 0, 4 * cnt + 2);
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btn_clear_Click(object sender, EventArgs e)
        {
            txbReceive.Text = "";
        }

        class CtrlData
        {
            public float[] data;
            public CtrlData()
            {
                data = new float[3];
                data[0] = data[1] = data[2] = 0;
            }
        }
        CtrlData ctrl = new CtrlData();

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (serialPort1.IsOpen)
            {
                
                if (keyData == Keys.Right)
                {
                    ctrl.data[1] -= 0.1f;
                    byte[] data_to_send = get_data_to_send(ctrl.data, 3);
                    serialPort1.Write(data_to_send, 0, 14);
                }

                if (keyData == Keys.Left)
                {
                    ctrl.data[1] += 0.1f;
                    byte[] data_to_send = get_data_to_send(ctrl.data, 3);
                    serialPort1.Write(data_to_send, 0, 14);
                }

                if (keyData == Keys.Up)
                {
                    ctrl.data[0] += 0.1f;
                    byte[] data_to_send = get_data_to_send(ctrl.data, 3);
                    serialPort1.Write(data_to_send, 0, 14);
                }
                if (keyData == Keys.Down)
                {
                    ctrl.data[0] -= 0.1f;
                    byte[] data_to_send = get_data_to_send(ctrl.data, 3);
                    serialPort1.Write(data_to_send, 0, 14);
                }
                if (keyData == Keys.Enter)
                {
                    ctrl = new CtrlData();
                    byte[] data_to_send = get_data_to_send(ctrl.data, 3);
                    serialPort1.Write(data_to_send, 0, 14);
                }
                if (keyData == Keys.A)
                {
                    ctrl.data[2] += 0.1f;
                    byte[] data_to_send = get_data_to_send(ctrl.data, 3);
                    serialPort1.Write(data_to_send, 0, 14);
                }
                if (keyData == Keys.D)
                {
                    ctrl.data[2] -= 0.1f;
                    byte[] data_to_send = get_data_to_send(ctrl.data, 3);
                    serialPort1.Write(data_to_send, 0, 14);
                }
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }
    }
}
